package br.com.gbvbahia.vendas.controllers.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

public class JsfUtil {

    public static final int LIMIT_AUTO_COMPLETE = 10;

    public static SelectItem[] getSelectItems(List<?> entities, boolean selectOne) {
        int size = selectOne ? entities.size() + 1 : entities.size();
        SelectItem[] items = new SelectItem[size];
        int i = 0;
        if (selectOne) {
            items[0] = new SelectItem("", "---");
            i++;
        }
        for (Object x : entities) {
            items[i++] = new SelectItem(x, x.toString());
        }
        return items;
    }

    public static void addErrorMessage(Exception ex, String defaultMsg) {
        String msg = ex.getLocalizedMessage();
        if (msg != null && msg.length() > 0) {
            addErrorMessage(msg);
        } else {
            addErrorMessage(defaultMsg);
        }
    }

    public static void addErrorMessages(List<String> messages) {
        for (String message : messages) {
            addErrorMessage(message);
        }
    }

    public static void addErrorMessage(String msg) {
        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
        FacesContext.getCurrentInstance().addMessage(null, facesMsg);
    }

    public static void addWarnMessage(String msg) {
        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_WARN, msg, msg);
        FacesContext.getCurrentInstance().addMessage(null, facesMsg);
    }

    public static void addSuccessMessage(String msg) {
        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg);
        FacesContext.getCurrentInstance().addMessage("successInfo", facesMsg);
    }

    public static String getRequestParameter(String key) {
        return FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(key);
    }

    public static Object getObjectFromRequestParameter(String requestParameterName, Converter converter, UIComponent component) {
        String theId = JsfUtil.getRequestParameter(requestParameterName);
        return converter.getAsObject(FacesContext.getCurrentInstance(), component, theId);
    }
    
     public static void genereteExcelReport(String reportName, JRBeanCollectionDataSource ds, FacesContext context) {
        HttpSession session = (HttpSession) context.getExternalContext().getSession(false);
        String path = session.getServletContext().getRealPath("WEB-INF" + File.separator + "jasper") + File.separator;
        String caminhoReport = path + reportName;
        Map<String, Object> parans = new HashMap<String, Object>();
        parans.put("SUBREPORT_DIR", path);
        JasperPrint impressao = null;
        try {
            // Gera o relatório
            impressao = JasperFillManager.fillReport(caminhoReport, parans, ds);
            // Escreve no OutputStream do response
            File fileReport = new File(diretorioPadrao("report"), gerarNomeFile("relatorio", "xls"));
            OutputStream outputfile = new FileOutputStream(fileReport);
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            
            JRXlsExporter exporterXLS = new JRXlsExporter();
            exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT, impressao);
            exporterXLS.setParameter(JRXlsExporterParameter.OUTPUT_STREAM, output);
            exporterXLS.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE);
            exporterXLS.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
            exporterXLS.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
            exporterXLS.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
            exporterXLS.exportReport();
            outputfile.write(output.toByteArray());
            
            JsfUtil.downloadFile(fileReport, context);
        } catch (JRException e) {
            e.printStackTrace();
        } catch (IOException io) {
            addErrorMessage("Erro de estrutura de arquivos ao tentar gerar o relatorio");
            io.printStackTrace();
        }
    }
     
         /**
     * Passe o arquivo e co contexto para que o cliente realize o download do
     * arquivo.<br> Utiliza o Servlet:
     * br.com.gbvbahia.servlet.ServletFileDownload
     *
     * @param file Arquivo a ser enviado ao usuário.
     * @param facesContext Contexto JSF
     */
    private static void downloadFile(final File file,
            final FacesContext facesContext) {
        String caminhoArquivo = file.getAbsolutePath();
        String nomeArquivo = file.getName();
        HttpServletResponse resp = (HttpServletResponse) facesContext.getExternalContext().getResponse();
        try {
            resp.sendRedirect(gerarUrlToDownload(facesContext, caminhoArquivo, nomeArquivo));
        } catch (IOException e) {
            e.printStackTrace();
        }
        facesContext.responseComplete();
    }
    
        /**
     * Gera uma url que pode ser utilizada para chamar o Servlel para baixar o
     * arquivo desejado.
     *
     * @param facesContext Contexto JSF
     * @param caminhoArquivo Caminho para o arquivo.
     * @param nomeArquivo Nome do arquivo.
     * @return String que pode ser utilziada como URL para baixar o arquivo.
     */
    private static String gerarUrlToDownload(final FacesContext facesContext,
            final String caminhoArquivo, final String nomeArquivo) {
        return facesContext.getExternalContext()
                .getRequestContextPath()
                + "/SFile?caminhoArquivo=" + caminhoArquivo
                + "&nomeArquivo=" + nomeArquivo;
    }
    
        /**
     * Retorna um java.io.File que representa o diretório padrão da aplicação.
     * tempdir/solida.<br> Sendo tempdir uma referência ao diretório
     * temporário da aplicação.
     *
     * @param loginUser Será criada uma pasta para os arquivos do usuário.
     * @return File apontando para tempdir/solida.
     */
    private static File diretorioPadrao(final String loginUser) {
        File f = new File(System.getProperty("java.io.tmpdir"));
        File f2 = new File(f, "margem");
        File toReturn = new File(f2,
                limparNomeFile(loginUser));
        toReturn.mkdirs();
        return toReturn;
    }
    
        /**
     * Retira caracteres nao aconselhaveis para nome de arquivo.
     *
     * @param loginUser
     * @return
     */
    private static String limparNomeFile(final String loginUser) {
        StringBuilder toReturn = new StringBuilder();
        for (int i = 0; i < loginUser.length(); i++) {
            if (StringUtils.isAlphanumeric(Character.toString(loginUser.charAt(i)))
                    || "_".equals(Character.toString(loginUser.charAt(i)))
                    || ".".equals(Character.toString(loginUser.charAt(i)))) {
                toReturn.append(Character.toString(loginUser.charAt(i)));
            }
        }
        return StringUtils.leftPad(toReturn.toString(), 5, "arqui");
    }
    
        /**
     * Gera o nome do arquivo concatenado com as data atual.
     *
     * @param nome
     * @param ext
     */
    private static String gerarNomeFile(String nome, String ext) {
        String agora = getDataFormatada(new Date(), "yyMMddHHmm");
        return limparNomeFile(nome) + agora + "." + ext;
    }
    
        
        /**
     * Formata a data para o pattern passado.
     *
     * @param date Se nulo retorna a data atual.
     * @param pattern O patter a ser formatado, não pode ser nulo.
     * @return
     */
    private static String getDataFormatada(final Date date, String pattern) {
        SimpleDateFormat sd = new SimpleDateFormat(pattern);
        if (date == null) {
            return sd.format(new Date());
        }
        return sd.format(date);
    }
    
        /**
     * Formata o valor passado para moeda Brasileira. 1,000.00 = R$ 1.000,00
     *
     * @param valor java.lang.Double a ser formatado.
     * @return java.lang.String valor formatado.
     */
    public static String formatCurrency(final Double valor) {
        NumberFormat nf = getCurencyNumberFormat();
        return nf.format(valor);
    }

    /**
     * Retorna um formatador para exibição de números financeiro:<br> Ex:
     * 65.7654 formata para R$ 65,77<br> Altera sua formatação será de acordo
     * com o padrão Brasileiro<br> Ex: 1,000.98 converte para 1.000,98.
     *
     * @return NumberFormat utilize o método format.
     */
    private static NumberFormat getCurencyNumberFormat() {
        NumberFormat nf =
                NumberFormat.getCurrencyInstance(new Locale("pt", "BR"));
        return nf;
    }
}